package com.boboPlanet.comm.log;

import com.boboPlanet.comm.entity.po.PlanetLogPO;
import com.boboPlanet.comm.utils.AutoGenerateIds;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description: TODO 日志读取处理
 * @Author: mis_wu
 * @Date: 2023/6/28
 * @Company planet
 **/
@Slf4j
public class LogReaderHandle {

    private static final String serve_prefix = "server_name:";

    private static final String trace_prefix = "traceId:";

    private static AtomicInteger autoMic;

    /**
     * 上一次读取位置
     */
    private static AtomicInteger preReadLoc;

    static {
        autoMic = new AtomicInteger(0);
        preReadLoc = new AtomicInteger(0);
    }

    /**
     * logback日志格式
     */
    private static final String logFormat = "%d{yyyy-MM-dd HH:mm:ss.SSS} server_name:${SERVER_NAME} traceId:%X{trace_id} [%thread] %-5level [%logger{50}] - %msg%n";

    public static List<PlanetLogPO> readLogs(String filePath) {
        List<PlanetLogPO> logs = new ArrayList<>();

        File file = new File(filePath);
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 解析日志行
                int currentVal = autoMic.incrementAndGet();
                preReadLoc.incrementAndGet();
                try {
                    PlanetLogPO log = parseLog(line);
                    logs.add(log);
                }catch (Exception e){
                    //错误那行是上一行的message报错，异常之后的那行追加到上一行,如果第一行解析异常，可能是错误，直接丢弃
                    if (!logs.isEmpty() && currentVal == 1){
                        PlanetLogPO currentLog = logs.get(currentVal);
                        currentLog.setMessage(currentLog.getMessage() + line);
                    }
                }
                //每200重新采集,避免OOM
                if (logs.size() > 201){
                    //todo:数据库保存一次

                    //清空
                    logs.clear();
                    //重新计数
                    autoMic.set(0);
                }

            }
        } catch (IOException e) {
            log.error("日志采集失败: {}",e.getMessage(),e);
        }

        return logs;
    }


    private static PlanetLogPO parseLog(String lineLog) {
        // 提取日期部分
        int dateStartIndex = 4;
        int dateEndIndex = logFormat.indexOf("}");
        String datePattern = logFormat.substring(dateStartIndex, dateEndIndex);

        //提取服务部分
        int serverNameStartIndex = lineLog.indexOf("server_name:") + 12;
        int serverNameEndIndex = lineLog.indexOf(" ", serverNameStartIndex);
        String serverName = lineLog.substring(serverNameStartIndex, serverNameEndIndex);

        // 提取traceId部分
        int traceIdStartIndex = lineLog.indexOf("traceId:") + 8;
        int traceIdEndIndex = lineLog.indexOf(" ", traceIdStartIndex);
        String traceId = lineLog.substring(traceIdStartIndex, traceIdEndIndex);

        // 提取线程部分
        int threadStartIndex = lineLog.indexOf("[", traceIdEndIndex) + 1;
        int threadEndIndex = lineLog.indexOf("]", threadStartIndex);
        String threadName = lineLog.substring(threadStartIndex, threadEndIndex);

        // 提取级别部分
        Pattern pattern = Pattern.compile("\\[(.*?)\\]\\s([A-Z]+)\\s");
        Matcher matcher = pattern.matcher(lineLog);
        String level = "";
        if (matcher.find()) {
            level = matcher.group(2);
        }

        // 提取logger部分
        int loggerStartIndex = lineLog.indexOf("[", lineLog.indexOf("[") + 1) + 1;
        int loggerEndIndex = lineLog.indexOf("]", loggerStartIndex);
        String logger = lineLog.substring(loggerStartIndex, loggerEndIndex);

        // 提取消息部分
        int messageStartIndex = loggerEndIndex + 3;
        String message = lineLog.substring(messageStartIndex);

        PlanetLogPO log = new PlanetLogPO();
        log.setLogId(AutoGenerateIds.getGenerateId());
        log.setTimeStamp(datePattern);
        log.setThreadName(threadName);
        log.setLevel(level);
        log.setServerName(serverName);
        log.setTraceId(traceId);
        log.setLogger(logger);
        log.setMessage(message);
        return log;

    }

}
